﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Gaea
{
    internal class GaeaOptionCache : IGaeaOptionCache
    {
        /// <summary>
        /// 数据库连接字符串与Gaea配置映射关系
        /// </summary>
        private Dictionary<string, GaeaOption> _connectionNameOptions;

        /// <summary>
        /// 各个DBConnection实现类与Gaea配置默认映射
        /// </summary>
        private Dictionary<RuntimeTypeHandle, GaeaOption> _baseTypeDefaultOptions;

        /// <summary>
        /// GaeaPower实现类型与Gaea配置映射
        /// </summary>
        private ConcurrentDictionary<RuntimeTypeHandle, GaeaOption> _gaeaPowerOption;

        /// <summary>
        /// 构造函数
        /// </summary>
        public GaeaOptionCache()
        {
            _connectionNameOptions = new Dictionary<string, GaeaOption>();
            _baseTypeDefaultOptions = new Dictionary<RuntimeTypeHandle, GaeaOption>();
            _gaeaPowerOption = new ConcurrentDictionary<RuntimeTypeHandle, GaeaOption>();
        }

        /// <summary>
        /// 组装GaeaPower与Gaea配置关联keyName
        /// </summary>
        /// <param name="runtimeTypeHandle">GaeaPower类型值</param>
        /// <param name="gaeaOption">Gaea配置实例</param>
        /// <returns></returns>
        private string BuildGaeaPowerOptionName(RuntimeTypeHandle runtimeTypeHandle, IGaeaOption gaeaOption)
        {
            return $"{runtimeTypeHandle.Value.ToString()}_{gaeaOption.ConnectionType}_{gaeaOption.ConnectionName}";
        }

        /// <summary>
        /// 添加Gaea配置
        /// </summary>
        /// <param name="gaeaOption">Gaea配置</param>
        public void AddGaeaOption(GaeaOption gaeaOption)
        {
            var gaeaPowerOptionName = BuildGaeaPowerOptionName(gaeaOption.BaseTypeGaeaPower.TypeHandle, gaeaOption);
            if (_connectionNameOptions.ContainsKey(gaeaPowerOptionName))
            {
                throw new ArgumentException($"Connection name {gaeaOption.ConnectionName} exists");
            }
            _connectionNameOptions.Add(gaeaPowerOptionName, gaeaOption);

            if (gaeaOption.ConnectionType == MultipleConnectionType.Default)
            {
                if (_baseTypeDefaultOptions.ContainsKey(gaeaOption.BaseTypeGaeaPower.TypeHandle))
                {
                    throw new ArgumentException($"Gaea power {nameof(gaeaOption.BaseTypeGaeaPower)} of default option exists");
                }
                _baseTypeDefaultOptions.Add(gaeaOption.BaseTypeGaeaPower.TypeHandle, gaeaOption);
            }
        }



        /// <summary>
        /// 获取Gaea配置
        /// </summary>
        /// <param name="gaeaPower">实现IGaeaPower实例</param>
        /// <returns></returns>
        public GaeaOption GetGaeaOption(Type typeOfGaeaPower)
        {
            if (_gaeaPowerOption.ContainsKey(typeOfGaeaPower.TypeHandle))
            {
                return _gaeaPowerOption[typeOfGaeaPower.TypeHandle];
            }
            var attributes = typeOfGaeaPower.GetCustomAttributes(true);
            GaeaOption gaeaOption = null;

            RuntimeTypeHandle runtimeTypeHandle = typeOfGaeaPower.BaseType.IsGenericType ? typeOfGaeaPower.BaseType.GetGenericTypeDefinition().TypeHandle : runtimeTypeHandle = typeOfGaeaPower.BaseType.TypeHandle;

            foreach (var item in attributes)
            {
                if (item is IGaeaOption)
                {
                    gaeaOption = _connectionNameOptions[BuildGaeaPowerOptionName(runtimeTypeHandle, item as IGaeaOption)];
                    break;
                }
            }
            if (gaeaOption == null)
            {
                if (!_baseTypeDefaultOptions.ContainsKey(runtimeTypeHandle))
                {
                    throw new ArgumentNullException($"Gaea power {nameof(typeOfGaeaPower.BaseType)}  option not exists");
                }
                gaeaOption = _baseTypeDefaultOptions[runtimeTypeHandle];
                _gaeaPowerOption.TryAdd(runtimeTypeHandle, gaeaOption);
            }
            return gaeaOption;
        }
    }
}

